﻿/// <summary>---------------------------------------------------------------------------///
/// 这是一个场景管理类，来源于Unity官方教程													///
/// wng0@sina.com																		///
/// 2019-6																				///
/// 2020-1-30 有两种写法																///
/// 一种是开场load一个场景，作为persistentScene的下级场景。后续场景全部是替换				///	
/// 另一种写法，开场不load场景。后续load场景，替换场景，unload场景，需要进行判断操作			///
/// 对比这两种写法，虽然第二种显得目的明确，但是多了很多判断。persistentscene的地位也变得模糊	///
/// 优选第一种写法，凸显persistentSence的管理者特性											///
/// </summary>--------------------------------------------------------------------------	///	
using System;
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
/// <summary>---------------------------------------------------------------------------///
/// This script exists in the Persistent scene and manages the content					///
/// based scene's loading.  It works on a principle that the							///
/// Persistent scene will be loaded first, then it loads the scenes that				///
/// contain the player and other visual elements when they are needed.					///
/// At the same time it will unload the scenes that are not needed when					///
/// the player leaves them.																///
/// </summary>--------------------------------------------------------------------------///
public class SceneController : MonoBehaviour
{
	public 	static 		SceneController Instance;
	private void Awake() 	
	{		Instance = this;	}
    public	CanvasGroup faderCanvasGroup;            									// The CanvasGroup that controls the Image used for fading to black.
    public 	float 		fadeDuration = 1f;                 								// How long it should take to fade to and from black.
    public 	string 		startingSceneName="BattleScene"; 								// The name of the scene that should be loaded first.
    public 	string 		initialStartingPositionName = "DoorToMarket"; 					// The name of the StartingPosition in the first scene to be loaded.  //  public SaveData playerSaveData;                 // Reference to the ScriptableObject which stores the name of the StartingPosition in the next scene.    
    private bool 		isFading;                         			 					// Flag used to determine if the Image is currently fading to or from black.
    private IEnumerator Start ()
    {		
		faderCanvasGroup.alpha = 1f;													// Set the initial alpha to start off with a black screen.
		//ConfigManager.Instance.ReadXMLAll();											//本意是优先loadingXML;但是放在这里显得突兀;最后很犹豫决定还是放在Configmanager的Awake里面.2020-1-29
        																				// Write the initial starting position to the playerSaveData so it can be loaded by the player when the first scene is loaded.
      																					// playerSaveData.Save (PlayerMovement.startingPositionKey, initialStartingPositionName);        
        																				// Start the first scene loading and wait for it to finish.
        yield return StartCoroutine (LoadSceneAndSetActive (startingSceneName));      	// Once the scene is finished loading, start fading in.
		if (DelegateManager.Instance.AfterSceneLoad != null) 							// If this event has any subscribers, call it.
		{							
			DelegateManager.Instance.AfterSceneLoad (startingSceneName);  
			Debug.Log("after sceneload");
		}
		StartCoroutine (Fade (0f));
    }
	// This is the main external point of contact and influence from the rest of the project.
	// This will be called by a SceneReaction when the player wants to switch scenes.
	public void FadeAndLoadScene (string sceneName)
	{
		if (!isFading)																	// If a fade isn't happening then start fading and switching scenes.
		{
			StartCoroutine (FadeAndSwitchScenes (sceneName));
		}
	}
	private IEnumerator FadeAndSwitchScenes (string sceneName)							// This is the coroutine where the 'building blocks' of the script are put together.
	{
		yield return StartCoroutine (Fade (1f));										// Start fading to black and wait for it to finish before continuing.
		if (DelegateManager.Instance.BeforeSceneUnload != null) 						// If this event has any subscribers, call it.
		{							
			DelegateManager.Instance.BeforeSceneUnload (SceneManager.GetActiveScene ().name.ToString ());
		}
		yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene().buildIndex);	// Unload the current active scene.
		yield return StartCoroutine (LoadSceneAndSetActive (sceneName));				// Start loading the given scene and wait for it to finish.
		if (DelegateManager.Instance.AfterSceneLoad != null) 							// If this event has any subscribers, call it.
		{							
			DelegateManager.Instance.AfterSceneLoad (sceneName);  
			Debug.Log("after sceneload");
		}
		yield return StartCoroutine (Fade (0f));										// Start fading back in and wait for it to finish before exiting the function.
	}
	private IEnumerator Fade (float finalAlpha)
	{
		isFading = true;																// Set the fading flag to true so the FadeAndSwitchScenes coroutine won't be called again
		faderCanvasGroup.blocksRaycasts = true;											// Make sure the CanvasGroup blocks raycasts into the scene so no more input can be accepted.
		float fadeSpeed = Mathf.Abs (faderCanvasGroup.alpha - finalAlpha) / fadeDuration;// Calculate how fast the CanvasGroup should fade based on it's current alpha, it's final alpha and how long it has to change between the two.
		while (!Mathf.Approximately (faderCanvasGroup.alpha, finalAlpha))				// While the CanvasGroup hasn't reached the final alpha yet...
		{
			faderCanvasGroup.alpha = Mathf.MoveTowards (faderCanvasGroup.alpha, finalAlpha,
				fadeSpeed * Time.deltaTime);												// ... move the alpha towards it's target alpha.
			yield return null; 															// Wait for a frame then continue.
		}
		isFading = false;																// Set the flag to false since the fade has finished.
		faderCanvasGroup.blocksRaycasts = false;										// Stop the CanvasGroup from blocking raycasts so input is no longer ignored.
	}
	private IEnumerator LoadSceneAndSetActive (string sceneName)
	{		
		yield return SceneManager.LoadSceneAsync (sceneName, LoadSceneMode.Additive);	// Allow the given scene to load over several frames and add it to the already loaded scenes (just the Persistent scene at this point).
		Scene newlyLoadedScene = SceneManager.GetSceneAt (SceneManager.sceneCount - 1);	// Find the scene that was most recently loaded (the one at the last index of the loaded scenes).
		SceneManager.SetActiveScene (newlyLoadedScene);									// Set the newly loaded scene as the active scene (this marks it as the one to be unloaded next).
	}
}
